#include "Main.h"

#include "Input.h"

#include "Timer.h"

Input::Input()
{
	memset(m_abCurrentMouseInput, 0, sizeof(bool) * INPUT_MOUSE_NUM_BUTTONS);
	memset(m_abPreviousMouseInput, 0, sizeof(bool) * INPUT_MOUSE_NUM_BUTTONS);

	m_uMousePositionX = 0;
	m_uMousePositionY = 0;

	m_uPreviousMousePositionX = 0;
	m_uPreviousMousePositionY = 0;

	memset(m_abPreviousKeyInput, 0, sizeof(bool) * INPUT_NUM_KEYS);
	memset(m_abCurrentKeyInput, 0, sizeof(bool) * INPUT_NUM_KEYS);

    m_szTextInputBuffer[0] = 0;
}

Input::~Input()
{
}

float Input::s_fClickRepeatTimer	= 0.0f;

void Input::SwapInputBuffers ()
{
	m_uPreviousMousePositionX = m_uMousePositionX;
	m_uPreviousMousePositionY = m_uMousePositionY;

    memcpy(m_abPreviousMouseInput, m_abCurrentMouseInput, sizeof(bool) * INPUT_MOUSE_NUM_BUTTONS);

    m_szTextInputBuffer[0] = 0;

	memcpy(m_abPreviousKeyInput,m_abCurrentKeyInput,sizeof(bool) * INPUT_NUM_KEYS);
}

void Input::HandleEvent ( const SDL_Event& xEvent )
{
	bool bDepress = false;

	switch( xEvent.type )
	{
		case SDL_MOUSEMOTION:
		{
			m_uMousePositionX = xEvent.motion.x;
			m_uMousePositionY = xEvent.motion.y;
		}
		break;

		case SDL_MOUSEBUTTONDOWN:
		{
			bDepress = true;
		}
		case SDL_MOUSEBUTTONUP:
		{
			switch(xEvent.button.button)
			{
				case SDL_BUTTON_LEFT:	m_abCurrentMouseInput[INPUT_MOUSE_BUTTON_LEFT]		= bDepress;	break;
				case SDL_BUTTON_RIGHT:	m_abCurrentMouseInput[INPUT_MOUSE_BUTTON_RIGHT]		= bDepress;	break;
				case SDL_BUTTON_MIDDLE:	m_abCurrentMouseInput[INPUT_MOUSE_BUTTON_MIDDLE]	= bDepress;	break;
			}
		}
		break;

		// TODO: FHandle mouse wheel

		case SDL_TEXTINPUT:
		{
            strncpy( m_szTextInputBuffer, xEvent.text.text, uINPUT_TEXTBUFFER_SIZE );
		}
        break;

		case SDL_KEYDOWN:
		case SDL_KEYUP:
		{
			#define KEY_CASE(x,y) case x: m_abCurrentKeyInput[ y ] = xEvent.key.state == SDL_PRESSED ? true : false; break

			switch( xEvent.key.keysym.scancode )
			{
				KEY_CASE( SDL_SCANCODE_UP, INPUT_KEY_CURSOR_UP );
				KEY_CASE( SDL_SCANCODE_DOWN, INPUT_KEY_CURSOR_DOWN );
				KEY_CASE( SDL_SCANCODE_LEFT, INPUT_KEY_CURSOR_LEFT );
				KEY_CASE( SDL_SCANCODE_RIGHT, INPUT_KEY_CURSOR_RIGHT );
				KEY_CASE( SDL_SCANCODE_BACKSPACE, INPUT_KEY_BACKSPACE );
				KEY_CASE( SDL_SCANCODE_DELETE, INPUT_KEY_DELETE );
				KEY_CASE( SDL_SCANCODE_HOME, INPUT_KEY_HOME );
				KEY_CASE( SDL_SCANCODE_END, INPUT_KEY_END );
				KEY_CASE( SDL_SCANCODE_RETURN, INPUT_KEY_RETURN );
				KEY_CASE( SDL_SCANCODE_TAB, INPUT_KEY_TAB );
				KEY_CASE( SDL_SCANCODE_ESCAPE, INPUT_KEY_ESC );
				KEY_CASE( SDL_SCANCODE_X, INPUT_KEY_CUT );
				KEY_CASE( SDL_SCANCODE_C, INPUT_KEY_COPY );	
				KEY_CASE( SDL_SCANCODE_V, INPUT_KEY_PASTE );
			}

			if( xEvent.key.keysym.scancode == SDL_SCANCODE_LCTRL || xEvent.key.keysym.scancode == SDL_SCANCODE_RCTRL || xEvent.key.keysym.scancode == SDL_SCANCODE_LGUI || xEvent.key.keysym.scancode == SDL_SCANCODE_RGUI )
			{
				m_abCurrentKeyInput[ INPUT_KEY_CTRL ] = xEvent.key.state == SDL_PRESSED ? true : false;
			}

			#undef KEY_CASE
		}
		break;
	}
}

bool Input::KeyPressed( const INPUT_KEY xKey ) const
{
	return ( m_abCurrentKeyInput[ xKey ] && !m_abPreviousKeyInput[ xKey ] );
}

bool Input::KeyDown( const INPUT_KEY xKey ) const
{
	return m_abCurrentKeyInput[ xKey ];
}

bool Input::KeyHeld( const INPUT_KEY xKey ) const
{
	return ( m_abCurrentKeyInput[ xKey ] && m_abPreviousKeyInput[ xKey ] );
}

bool Input::KeyReleased( const INPUT_KEY xKey ) const
{
	return ( !m_abCurrentKeyInput[ xKey ] && m_abPreviousKeyInput[ xKey ] );
}

bool Input::MouseButtonPressed (const INPUT_MOUSE_BUTTON xButton) const
{
	return (m_abCurrentMouseInput[xButton] && !m_abPreviousMouseInput[xButton]);
}

bool Input::MouseButtonDoubleClick (const INPUT_MOUSE_BUTTON xButton) const
{
	s_fClickRepeatTimer += Timer::GetFrameTime();
	
	if( m_abCurrentMouseInput[xButton] && !m_abPreviousMouseInput[xButton] )
	{
		bool bReturnValue = s_fClickRepeatTimer < 0.35f;
		s_fClickRepeatTimer = 0.0f;
		return bReturnValue;
	}
	
	return false;
}

bool Input::MouseButtonHeld (const INPUT_MOUSE_BUTTON xButton) const
{
	return m_abCurrentMouseInput[xButton];
}

bool Input::MouseButtonReleased	(const INPUT_MOUSE_BUTTON xButton) const
{
	return (m_abPreviousMouseInput[xButton] && !m_abCurrentMouseInput[xButton]);
}

bool Input::MouseMoved () const
{
	return ( ( m_uMousePositionX != m_uPreviousMousePositionX ) || ( m_uMousePositionY != m_uPreviousMousePositionY) );
}

u_int Input::MousePositionX	() const
{
	return m_uMousePositionX;
}

u_int Input::MousePositionY () const
{
	return m_uMousePositionY;
}

void Input::FlushInput ()
{
	memset(m_abCurrentKeyInput,		0,sizeof(bool) * INPUT_NUM_KEYS);
	memset(m_abPreviousKeyInput,	0,sizeof(bool) * INPUT_NUM_KEYS);

	memset(m_abCurrentMouseInput,	0,sizeof(bool) * INPUT_MOUSE_NUM_BUTTONS);
	memset(m_abPreviousMouseInput,	0,sizeof(bool) * INPUT_MOUSE_NUM_BUTTONS);

	//Dont lose the mouse position, but set the previous cursor position so
	//we wont report 'mouse moved'
	m_uPreviousMousePositionX = m_uMousePositionX;
	m_uPreviousMousePositionY = m_uMousePositionY;
}

void Input::SetCursor( const INPUT_MOUSE_CURSOR xCursor )
{
	Platform_SetCursor( xCursor );
}

// _______________________________________________________________________________________

char* Clipboard::s_szClipboard = 0;

void Clipboard::Initialise()
{
	s_szClipboard = new char[ iCLIPBOARD_DATA_SIZE ];
}

void Clipboard::Shutdown()
{
	delete []s_szClipboard;
	s_szClipboard = 0;
}

void Clipboard::CopyToClipboard( const char* szText, u_int uLen )
{
	strncpy( s_szClipboard, szText, MACRO_MIN( uLen, (u_int)iCLIPBOARD_DATA_SIZE - 1 ) );
	s_szClipboard[ MACRO_MIN( uLen, (u_int)iCLIPBOARD_DATA_SIZE - 1 ) ] = 0;
	Platform_Copy();
}

const char* Clipboard::GetClipboardData()
{
	Platform_Paste();
	return s_szClipboard;
}


//eof

